using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input.Touch;


namespace Risiko
{
  public class Polygon
  {
    public List<Point> Points;
    public Point Center;

    public Polygon() 
    {
      Points = new List<Point>();
    }
  }

  public class MapGenerator : Microsoft.Xna.Framework.DrawableGameComponent
  {
    SpriteBatch spriteBatch;
    State.State gameState;

    Texture2D white, circle;
    SpriteFont font;

    Polygon p;

    public MapGenerator(Game game)
      : base(game)
    {
      spriteBatch = this.Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;

      // Add state service
      gameState = new State.State();
      Game.Services.AddService(typeof(State.State), gameState);

      //gameState = game.Services.GetService(typeof(State.State)) as State.State;
    }

    List<Texture2D> terr = new List<Texture2D>();

    public override void Initialize()
    {
      // Initialize fake game state
      gameState.board = State.State.GetClassicBoard();
      //CreateMap();

      white = Game.Content.Load<Texture2D>(@"white_pixel");
      circle = Game.Content.Load<Texture2D>(@"Images\\Board\\Circle");
      font = Game.Content.Load<SpriteFont>(@"small_font");

      terr.Add(Game.Content.Load<Texture2D>(@"t1"));
      terr.Add(Game.Content.Load<Texture2D>(@"t2"));
      terr.Add(Game.Content.Load<Texture2D>(@"t3"));
      terr.Add(Game.Content.Load<Texture2D>(@"t4"));
      terr.Add(Game.Content.Load<Texture2D>(@"t5"));
      terr.Add(Game.Content.Load<Texture2D>(@"t6"));
      terr.Add(Game.Content.Load<Texture2D>(@"t7"));
      terr.Add(Game.Content.Load<Texture2D>(@"t8"));
      terr.Add(Game.Content.Load<Texture2D>(@"t9"));


      p = new Polygon();
      p.Points.Add(new Point(10, 10));
      p.Points.Add(new Point(400, 50));
      p.Points.Add(new Point(500, 300));
      p.Points.Add(new Point(100, 400));
      p.Points.Add(new Point(200, 200));
      
      base.Initialize();
    }

    public void CreateMap()
    {
      // Crea Board
      gameState.board = new State.Board();
      gameState.board.continents = new State.Continent[4];

      for (int i = 0; i < gameState.board.continents.Length; i++)
      {
        State.Continent c = CreateContinent();
        c.name = "C" + i;

        for (int t = 0; t < c.territories.Count(); t++)
        {
          c.territories[t].continentID = i;
          c.territories[t].neighbors = new State.TerritoryReference[c.territories.Count() - 1];

          for (int t2 = 0; t2 < c.territories.Count(); t2++)
          {
            if (c.territories[t].territoryID != c.territories[t2].territoryID)
            c.territories[t].neighbors[t2] = new State.TerritoryReference() { continentID = c.territories[t].continentID, territoryID = c.territories[t].territoryID };
          }
        }
          gameState.board.continents[i] = c;
      }   
    }

    public State.Continent CreateContinent()
    {
      Random rnd = new Random();
      List<State.Territory> territories = new List<State.Territory>();

      for (int j = 0; j < 8; j++)
        for (int i = 0; i < 14; i++)
        {
          //territories.Add(new State.Territory() { position = new Vector2((50 * i) + 100, (50 * j) + 70) });
          territories.Add(new State.Territory() { position = new Vector2((int)rnd.Next(50, 750), (int)rnd.Next(50, 430)) });
        }

      for (int i = 0; i < 10; i++)
      {
        State.Territory t = new State.Territory() { position = new Vector2((int)rnd.Next(50, 700), (int)rnd.Next(50, 430)) };

        for (int j = 0; j < territories.Count; j++)
        {
          if (Vector2.Distance(t.position, territories[j].position) < 200)
          {
            territories.Add(t);
            territories.Remove(territories[j]);
          }
        }

      }

      State.Territory tn = new State.Territory() { position = territories[0].position };
      List<State.Territory> tl = new List<State.Territory>();

      int Count = 0;
      for (int i = 0; i < territories.Count; i++)
      {
        if (Vector2.Distance(tn.position, territories[i].position) < 300)
        {
          Count++;
          if (Count < 7)
            tl.Add(territories[i]);
        }
      }

      State.Continent c = new State.Continent();
      c.territories = tl.ToArray();

      return c;
    }

    public override void Update(GameTime gameTime)
    {
      if (TouchPanel.IsGestureAvailable)
      {
        GestureSample gesture = TouchPanel.ReadGesture();

        if (gesture.GestureType == GestureType.Tap)
        {
          Vector2 v = gesture.Position;
          CreateMap();
        }
      }

      base.Update(gameTime);
    }

    public void DrawPolygon(Polygon p, Color c)
    {
      for (int i = 0; i < p.Points.Count; i++)
      {
        spriteBatch.Draw(white, new Rectangle(p.Points[i].X, p.Points[i].Y, 3, 3), Color.Red);
        int j = (i + 1) % p.Points.Count;
        DrawLine(p.Points[i], p.Points[j], c);
      }    
    }

    public void DrawFillPolygon(Polygon p, Color c)
    {
      int MaxX = 0, MaxY = 0, MinX = 800, MinY = 480;
      for (int i = 0; i < p.Points.Count; i++)
      {
        if (p.Points[i].X < MinX) MinX = p.Points[i].X;
        if (p.Points[i].X > MaxX) MaxX = p.Points[i].X;
        if (p.Points[i].Y < MinY) MinY = p.Points[i].Y;
        if (p.Points[i].Y > MaxY) MaxY = p.Points[i].Y;
      }

      p.Center.X = (MaxX - MinX) / 2;
      p.Center.Y = (MaxY - MinY) / 2;

      Vector2 pStart = new Vector2 (p.Center.X, p.Center.Y);
      c.A = 150; // Prova

      for (int i = 0; i < p.Points.Count; i++)
      {
        spriteBatch.Draw(white, new Rectangle(p.Points[i].X, p.Points[i].Y, 3, 3), c);
        int j = (i + 1) % p.Points.Count;

        Vector2 p1 = new Vector2 (p.Points[i].X, p.Points[i].Y);
        Vector2 p2 = new Vector2 (p.Points[j].X, p.Points[j].Y);

        var linkAngle = (float)Math.Atan2(p2.Y - p1.Y, p2.X - p1.X);
        var linkLen = Vector2.Distance(p1, p2);

        for (int k = 1; k < linkLen; k++)
        {
          Vector2 p3 = Vector2.Lerp(p1, p2, (float)(k / linkLen));
          DrawLine(pStart, p3, c);
        }
      }

      spriteBatch.Draw(white, new Rectangle((int)p.Center.X, (int)p.Center.Y, 3, 3), Color.Black);
    }

    public void DrawLine(Point p1, Point p2, Color c)
    { 
      DrawLine(new Vector2 (p1.X, p1.Y), new Vector2 (p2.X, p2.Y), c);
    }

    public void DrawLine(Vector2 p1, Vector2 p2, Color c)
    {
      var linkAngle = (float)Math.Atan2(p2.Y - p1.Y, p2.X - p1.X);
      var linkLen = Vector2.Distance(p1, p2);
      spriteBatch.Draw(white, p1, null, c, linkAngle, Vector2.Zero, new Vector2(linkLen, 1), SpriteEffects.None, 0.0f);
    }

    public void DrawMap()
    {
      Color c= new Color(100, 234, 213, 150);
      Random rnd = new Random();

      gameState.board.IterTerritories(t =>
      {
        // Draw territories
        var position = t.position;

        c.R = (byte)(t.position.X); //(byte)rnd.Next(0,250);
        c.G = (byte)(t.position.Y);//(byte)rnd.Next(0,250);
        c.B = (byte)(t.position.X);//(byte)rnd.Next(0,250);

        //DrawPolygon(CreatePolygon(t), c);
        CreateCaos(t);

        // Draw links
        if (t.neighbors != null)
        for (int k = 0; k < t.neighbors.Count(); ++k)
        {
          var linkStart = t.position;
          var linkEndTId = t.neighbors[k].territoryID;
          var linkEndCId = t.neighbors[k].continentID;
          var linkEnd = gameState.board.continents[linkEndCId].territories[linkEndTId].position;

          var linkAngle = (float)Math.Atan2(linkEnd.Y - linkStart.Y, linkEnd.X - linkStart.X);
          var linkLen = Vector2.Distance(linkStart, linkEnd);
          spriteBatch.Draw(white, linkStart, null, Color.Gray, linkAngle, Vector2.Zero, new Vector2(linkLen, 1), SpriteEffects.None, 1.0f);
        }

        spriteBatch.Draw(white, new Rectangle((int)position.X, (int)position.Y, 3, 3), Color.Black);
      });
    }

    public Polygon CreatePolygon(State.Territory t)
    {
      Polygon p = new Polygon();

      for (int i = 0; i < t.neighbors.Length; i++)
      {
        State.Territory t2 = gameState.board.GetTerritory(t.neighbors[i]);

        p.Points.Add(new Point((int)t2.position.X, (int)t2.position.Y));
      }     
        return p;
    }

    public void CreateCaos(State.Territory t)
    {
      int indexID = t.continentID + t.territoryID;
      indexID %= terr.Count;
      Color IdColor = Color.White;

      int deltaColor = 10;
      if(t.neighbors != null)
        deltaColor = 255 / (t.neighbors.Length * 2);

      if (t.continentID == 0) { IdColor = Color.DarkRed; }
      if (t.continentID == 1) IdColor = Color.DarkMagenta;
      if (t.continentID == 2) IdColor = Color.DarkOliveGreen;
      if (t.continentID == 3) IdColor = Color.DarkBlue;
      if (t.continentID == 4) IdColor = Color.Green;
      if (t.continentID == 5) IdColor = Color.DarkGoldenrod;
      IdColor.R += (byte)(deltaColor);
      IdColor.G += (byte)(deltaColor);
      IdColor.B += (byte)(deltaColor);

      int dist = 100;
      if(t.neighbors != null)
        dist = (int)Vector2.Distance(t.position, gameState.board.GetTerritory(t.neighbors[0]).position);

      int mindist = 1000;
      if (t.neighbors != null)
      for (int i = 0; i < t.neighbors.Length; i++)
      {
        dist = (int)Vector2.Distance(t.position, gameState.board.GetTerritory(t.neighbors[i]).position);
        if (dist < mindist) mindist = dist;
      }

      float rotation = (float)Math.Atan2(1 - t.position.Y, 1 - t.position.X);

      if(dist < 200)
      spriteBatch.Draw(terr[indexID], new Rectangle((int)t.position.X, (int)t.position.Y, dist, dist), null, IdColor, rotation, new Vector2(terr[indexID].Bounds.Center.X, terr[indexID].Bounds.Center.Y), SpriteEffects.None, 0.6f);

      if (t.neighbors != null)
      for (int i = 0; i < t.neighbors.Length; i++)
      {
        State.Territory t2 = gameState.board.GetTerritory(t.neighbors[i]);

        //DrawMacchia(t2);
        indexID = t2.continentID + t2.territoryID;
        indexID %= terr.Count;
        dist = (int)Vector2.Distance(t.position, gameState.board.GetTerritory(t.neighbors[i]).position);
        rotation = (float)Math.Atan2(t2.position.Y - t.position.Y, t2.position.X - t.position.X);

        if(dist < 150)
        spriteBatch.Draw(terr[indexID], new Rectangle((int)t.position.X, (int)t.position.Y, dist, dist), null, IdColor, rotation, new Vector2(terr[indexID].Bounds.Center.X, terr[indexID].Bounds.Center.Y), SpriteEffects.None, 0.5f);

      }
    }

    public override void Draw(GameTime gameTime)
    {
      spriteBatch.Begin();

      DrawMap();

      spriteBatch.End();
      base.Draw(gameTime);
    }
  }
}
